package fi.foyt.cs.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.apache.commons.lang3.math.NumberUtils;

import com.restfb.util.StringUtils;

import fi.foyt.cs.Settings;
import fi.foyt.cs.api.SystemProperty;
import fi.foyt.cs.persistence.dao.items.InventoryDAO;
import fi.foyt.cs.persistence.dao.items.InventoryItemDAO;
import fi.foyt.cs.persistence.dao.items.ItemDAO;
import fi.foyt.cs.persistence.dao.user.UserDAO;
import fi.foyt.cs.persistence.dao.user.UserFriendDAO;
import fi.foyt.cs.persistence.dao.user.UserIdentifierDAO;
import fi.foyt.cs.persistence.dao.user.UserLocationDAO;
import fi.foyt.cs.persistence.domainmodel.items.Inventory;
import fi.foyt.cs.persistence.domainmodel.items.InventoryItem;
import fi.foyt.cs.persistence.domainmodel.items.Item;
import fi.foyt.cs.persistence.domainmodel.user.User;
import fi.foyt.cs.persistence.domainmodel.user.UserFriend;
import fi.foyt.cs.persistence.domainmodel.user.UserIdentifier;
import fi.foyt.cs.persistence.domainmodel.user.UserLocation;

public class UserController {

  public User createUser(String firstName, String lastName, String email, Locale locale, Boolean licenseAgreed) {
    UserDAO userDAO = new UserDAO();
    InventoryDAO inventoryDAO = new InventoryDAO();
    InventoryItemDAO inventoryItemDAO = new InventoryItemDAO();
    ItemDAO itemDAO = new ItemDAO();
    
    Double initialMoney = Settings.getDoubleValue(SystemProperty.SETTINGS_INITIAL_MONEY);
    if (initialMoney == null)
      initialMoney = 0.00;
    
    User user = userDAO.create(firstName, lastName, email, locale.toString(), licenseAgreed);
    Inventory inventory = inventoryDAO.create(user.getId().getId(), initialMoney);
    
    String initialItemsSetting = Settings.getValue(SystemProperty.SETTINGS_INITIAL_ITEMS);
    if (!StringUtils.isBlank(initialItemsSetting)) {
      String[] initialItems = initialItemsSetting.split(",");
      for (String initialItem : initialItems) {
        Long itemId = NumberUtils.createLong(initialItem);
        Item item = itemDAO.findById(itemId); 
        inventoryItemDAO.create(inventory.getId().getId(), item.getId().getId(), new Integer(1));
      }
    }
    
    return user;
  }
  
  public User findUserById(Long id) {
    UserDAO userDAO = new UserDAO();
    return userDAO.findById(id);
  }
  
  public User findUserByEmail(String email) {
    UserDAO userDAO = new UserDAO();
    return userDAO.findByEmail(email);
  }
  
  public User findUserByUserIdentifier(UserIdentifier userIdentifier) {
    return findUserById(userIdentifier.getUserId());
  }
  
  public User findUserByIdentifier(String identifier) {
    UserIdentifierDAO userIdentifierDAO = new UserIdentifierDAO();
    UserIdentifier userIdentifier = userIdentifierDAO.findByIdentifier(identifier);
    if (userIdentifier != null) {
      return findUserByUserIdentifier(userIdentifier);
    }
    
    return null;
  }
  
  public List<User> listUsers() {
    UserDAO userDAO = new UserDAO();
    return userDAO.listAll();
  }
  
  public List<User> listUsers(int firstResult, int maxResults) {
    UserDAO userDAO = new UserDAO();
    return userDAO.listAll(firstResult, maxResults);
  }
  
  public List<User> listUsersByMaxDistanceAndLastUpdated(Double lat, Double lng, Double maxDistance, Long updated, int maxResults) {
    List<User> users = new ArrayList<User>();
    
    UserLocationDAO userLocationDAO = new UserLocationDAO();
    List<UserLocation> userLocations = userLocationDAO.listByMaxDistanceAndLastUpdated(lat, lng, maxDistance, updated, maxResults);
    for (UserLocation userLocation : userLocations) {
      users.add(findUserById(userLocation.getUserId()));
    }
    
    return users;
  }
  
  public List<User> listUserFriends(User user) {
    List<User> result = new ArrayList<User>();
    
    List<UserFriend> userFriends = listUserFriendsByUser(user);
    List<UserFriend> friendUsers = listUserFriendsByFriend(user);
    List<Long> friendIds = new ArrayList<Long>();
    
    for (UserFriend userFriend : userFriends) {
      friendIds.add(userFriend.getFriendId());
    }
    
    for (UserFriend friendUser : friendUsers) {
      if (!friendUser.getUserId().equals(user.getId()) && !friendIds.contains(user.getId())) {
        friendIds.add(friendUser.getUserId());
      }
    }
    
    for (Long friendId : friendIds) {
      result.add(findUserById(friendId));
    }
    
    return result;
  }
  
  public List<User> listUserFriendsAndConfirmed(User user, Boolean confirmed) {
    List<User> result = new ArrayList<User>();
    
    List<UserFriend> userFriends = listUserFriendsByUserAndConfirmed(user, confirmed);
    List<UserFriend> friendUsers = listUserFriendsByFriendAndConfirmed(user, confirmed);
    List<Long> friendIds = new ArrayList<Long>();
    
    for (UserFriend userFriend : userFriends) {
      friendIds.add(userFriend.getFriendId());
    }
    
    for (UserFriend friendUser : friendUsers) {
      if (!friendUser.getUserId().equals(user.getId()) && !friendIds.contains(user.getId())) {
        friendIds.add(friendUser.getUserId());
      }
    }
    
    for (Long friendId : friendIds) {
      result.add(findUserById(friendId));
    }
    
    return result;
  }
  
  public Integer countUsers() {
    UserDAO userDAO = new UserDAO();
    return userDAO.count();
  }
  
  public void deleteUser(User user) {
    UserDAO userDAO = new UserDAO();
    userDAO.delete(user);
  }
  
  public UserIdentifier createUserIdentifier(User user, String identifier) {
    UserIdentifierDAO userIdentifierDAO = new UserIdentifierDAO();
    return userIdentifierDAO.create(user.getId().getId(), identifier);
  }
  
  public UserIdentifier findUserIdentifierById(Long id) {
    UserIdentifierDAO userIdentifierDAO = new UserIdentifierDAO();
    return userIdentifierDAO.findById(id);
  }
  
  public UserIdentifier findUserIdentifierByIdentifier(String identifier) {
    UserIdentifierDAO userIdentifierDAO = new UserIdentifierDAO();
    return userIdentifierDAO.findByIdentifier(identifier);
  }
  
  public List<UserIdentifier> listUserIdentifiersByUser(User user) {
    UserIdentifierDAO userIdentifierDAO = new UserIdentifierDAO();
    return userIdentifierDAO.listByUserId(user.getId().getId());
  }
  
  public void deleteUserIdentifier(UserIdentifier userIdentifier) {
    UserIdentifierDAO userIdentifierDAO = new UserIdentifierDAO();
    userIdentifierDAO.delete(userIdentifier);
  }
  
  public Inventory updateInventoryMoney(Inventory inventory, Double money) {
    InventoryDAO inventoryDAO = new InventoryDAO();
    return inventoryDAO.updateMoney(inventory, money);
  }
  
  public Inventory findInventoryById(Long id) {
    InventoryDAO inventoryDAO = new InventoryDAO();
    return inventoryDAO.findById(id);
  }

  public Inventory findInventoryByUser(User user) {
    InventoryDAO inventoryDAO = new InventoryDAO();
    return inventoryDAO.findByUserId(user.getId().getId());
  }
  
  public void deleteInventory(Inventory inventory) {
    InventoryDAO inventoryDAO = new InventoryDAO();
    inventoryDAO.delete(inventory);
  }
  
  public InventoryItem createInventoryItem(Inventory inventory, Item item, Integer count) {
    InventoryItemDAO inventoryItemDAO = new InventoryItemDAO();
    return inventoryItemDAO.create(inventory.getId().getId(), item.getId().getId(), count);
  }
  
  public InventoryItem findInventoryItemById(Long inventoryItemId) {
    InventoryItemDAO inventoryItemDAO = new InventoryItemDAO();
    return inventoryItemDAO.findById(inventoryItemId);
  }
    
  public InventoryItem findInventoryItemByInventoryAndItem(Inventory inventory, Item item) {
    InventoryItemDAO inventoryItemDAO = new InventoryItemDAO();
    return inventoryItemDAO.findByInventoryIdAndItemId(inventory.getId().getId(), item.getId().getId());
  }

  public List<InventoryItem> listInventoryItems(Inventory inventory) {
    InventoryItemDAO inventoryItemDAO = new InventoryItemDAO();
    return inventoryItemDAO.listByInventoryId(inventory.getId().getId());
  }
  
  public InventoryItem updateInventoryItemCount(InventoryItem inventoryItem, Integer count) {
    InventoryItemDAO inventoryItemDAO = new InventoryItemDAO();
    return inventoryItemDAO.updateCount(inventoryItem, count);
  }
  
  public void deleteInventoryItem(InventoryItem inventoryItem) {
    InventoryItemDAO inventoryItemDAO = new InventoryItemDAO();
    inventoryItemDAO.delete(inventoryItem);
  }
  
  public UserLocation createUserLocation(User user, Double latitude, Double longitude) {
    UserLocationDAO userLocationDAO = new UserLocationDAO();
    return userLocationDAO.create(user.getId().getId(), latitude, longitude);
  }
  
  public UserLocation findUserLocationByUser(User user) {
    UserLocationDAO userLocationDAO = new UserLocationDAO();
    return userLocationDAO.findByUserId(user.getId().getId());
  }
  
  public UserLocation updateUserLocation(UserLocation userLocation, Double latitude, Double longitude) {
    UserLocationDAO userLocationDAO = new UserLocationDAO();
    return userLocationDAO.update(userLocation, latitude, longitude);
  }
  
  public void deleteUserLocation(UserLocation userLocation) {
    UserLocationDAO userLocationDAO = new UserLocationDAO();
    userLocationDAO.delete(userLocation);
  }
  
  public UserFriend createUserFriend(User user, User friend, Boolean confirmed) {
    UserFriendDAO userFriendDAO = new UserFriendDAO();
    return userFriendDAO.create(user.getId().getId(), friend.getId().getId(), confirmed);
  }
  
  public UserFriend updateUserFriendConfirmed(UserFriend userFriend, Boolean confirmed) {
    UserFriendDAO userFriendDAO = new UserFriendDAO();
    return userFriendDAO.updateConfirmed(userFriend, confirmed);
  }
  
  public UserFriend findUserFriendById(Long userFriendId) {
    UserFriendDAO userFriendDAO = new UserFriendDAO();
    return userFriendDAO.findById(userFriendId);
  }

  public UserFriend findUserFriendByUserAndFriend(User user, User friend) {
    UserFriendDAO userFriendDAO = new UserFriendDAO();
    UserFriend userFriend = userFriendDAO.findByUserIdAndFriendId(user.getId().getId(), friend.getId().getId());
    return userFriend;
  }

  public List<UserFriend> listUserFriendsByUser(User user) {
    UserFriendDAO userFriendDAO = new UserFriendDAO();
    return userFriendDAO.listByUserId(user.getId().getId());
  }
  
  public List<UserFriend> listUserFriendsByFriend(User friend) {
    UserFriendDAO userFriendDAO = new UserFriendDAO();
    return userFriendDAO.listByFriendId(friend.getId().getId());
  }
  
  public List<UserFriend> listUserFriendsByUserAndConfirmed(User user, Boolean confirmed) {
    UserFriendDAO userFriendDAO = new UserFriendDAO();
    return userFriendDAO.listByUserIdAndConfirmed(user.getId().getId(), confirmed);
  }
  
  public List<UserFriend> listUserFriendsByFriendAndConfirmed(User friend, Boolean confirmed) {
    UserFriendDAO userFriendDAO = new UserFriendDAO();
    return userFriendDAO.listByFriendIdAndConfirmed(friend.getId().getId(), confirmed);
  }
  
  public void deleteUserFriend(UserFriend userFriend) {
    UserFriendDAO userFriendDAO = new UserFriendDAO();
    userFriendDAO.delete(userFriend);
  }
}
